package com.tianji.learning.service.impl;

import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.RedisConstants;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.query.PointsBoardQuery;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author 林云
 * @since 2023-08-18
 */
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {

    private final StringRedisTemplate redisTemplate;

    private final UserClient userClient;

    /**
     * 查询积分榜-当前赛季或历史赛季
     * 当前赛季从redis获取 历史赛季从mysql中获取
     */
    @Override
    public PointsBoardVO queryPointBoardList(PointsBoardQuery query) {
        // 1.获取登录用户
        Long userId = UserContext.getUser();
        // 2.判断是当前赛季还是历史赛季
        Long season = query.getSeason();
        boolean isCurrent = season == null || season == 0;
        // 3.查询我的积分和排名
        LocalDate now = LocalDate.now();
        String yearAndMonth = DateUtils.format(now, "yyyyMM");
        String key = RedisConstants.POINTS_BOARD_KEY_PREFIX + yearAndMonth;//获取key
        PointsBoard board = isCurrent ? queryMyCurrentBoard(key) : queryMyHistoryBoard(key);
        // 4.分页查询赛季积分榜
        List<PointsBoard> list = isCurrent
                ? queryCurrentBoard(key, query.getPageNo(), query.getPageSize())
                : queryHistoryBoard(query);
        // 5.封装返回
        PointsBoardVO vo = new PointsBoardVO();
        vo.setRank(board.getRank());
        vo.setPoints(board.getPoints());
        List<PointsBoardItemVO> voList = new ArrayList<>();
        // 5.1远程调用获取用户集合
        List<Long> userIdList = list.stream().map(PointsBoard::getUserId).collect(Collectors.toList());
        List<UserDTO> userList = userClient.queryUserByIds(userIdList);
        if (CollUtils.isEmpty(userList)) {
            throw new BizIllegalException("用户不存在");
        }
        // 5.2将用户集合封装为map
        Map<Long, String> userMap = userList.stream().collect(Collectors.toMap(UserDTO::getId, c -> c.getName()));
        // 5.3批量封装成PointsBoardItemVO
        for (PointsBoard pointsBoard : list) {
            PointsBoardItemVO itemVO = new PointsBoardItemVO();
            String name = userMap.get(pointsBoard.getUserId());
            itemVO.setName(name);
            itemVO.setRank(pointsBoard.getRank());
            itemVO.setPoints(pointsBoard.getPoints());
            voList.add(itemVO);
        }
        vo.setBoardList(voList);
        return vo;
    }

    /**
     * 查询当前赛季 我的积分与排名
     */
    private PointsBoard queryMyCurrentBoard(String key) {
        Long userId = UserContext.getUser();
        //获取分数
        Double points = redisTemplate.opsForZSet().score(key, userId.toString());
        //获取排名
        Long rank = redisTemplate.opsForZSet().reverseRank(key, userId.toString());
        PointsBoard pointsBoard = new PointsBoard();
        pointsBoard.setPoints(points == null ? 0 : points.intValue());
        pointsBoard.setRank(rank == null ? 0 : rank.intValue() + 1);
        return pointsBoard;
    }

    /**
     * 查询当前赛季 积分榜
     * start = (pageNo -1 ) * pageSize
     * end = start + pageSize - 1
     */
    @Override
    public List<PointsBoard> queryCurrentBoard(String key, Integer pageNo, Integer pageSize) {
        //计算start和end
        int start = (pageNo - 1) * pageSize;
        int end = start + pageSize - 1;
        //分数降序 分页查询
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet()
                .reverseRangeWithScores(key, start, end);
        if (CollUtils.isEmpty(typedTuples)) {
            return CollUtils.emptyList();
        }
        List<PointsBoard> list = new ArrayList<>();
        int rank = start + 1; //redis从0开始, 但我们要求排名从1开始, 翻页后不能是序号
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            PointsBoard board = new PointsBoard();
            Long userId = Long.valueOf(tuple.getValue());//值即用户id
            Integer points = tuple.getScore().intValue();//分数即积分
            if (userId == null || points == null) {
                continue;
            }
            board.setUserId(userId);
            board.setPoints(points);
            board.setRank(rank++);
            list.add(board);
        }
        return list;
    }

    /**
     * 查询历史赛季我的积分与排名
     */
    private PointsBoard queryMyHistoryBoard(String key) {
        return null;
    }

    /**
     * 查询历史赛季积分榜
     */
    private List<PointsBoard> queryHistoryBoard(PointsBoardQuery query) {
        return null;
    }

}
